package psn.zjk.common.jdk8;

import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author zhangjk
 * @CREATE_TIME 2021/1/16 16:54
 */
public class BlockQueuePerformanceTest {

    public static void main(String[] args) {
        SyncQueue syncQueue = new SyncQueue();
        ReadWriteQueue readWriteQueue = new ReadWriteQueue();
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        executorService.execute(() -> {
            while (true) {
                readWriteQueue.add("");
//                syncQueue.add("");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        executorService.execute(() -> {
            while (true) {
                try {
                    readWriteQueue.pop();
//                    syncQueue.pop();
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        executorService.execute(() -> {
            while (true) {
                try {
                    readWriteQueue.pop();
//                    syncQueue.pop();
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        executorService.execute(() -> {
            long last=0;
            while (true) {
                last = System.currentTimeMillis();
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                long s=(System.currentTimeMillis()-last)/1000;
                System.out.println(readWriteQueue.count()/s);
//                System.out.println(syncQueue.count()/s);
            }
        });

    }

    static class SyncQueue {
        private HashMap<String, String> map = new HashMap<>();
        private AtomicInteger count = new AtomicInteger();

        public synchronized void add(String data) {
            map.put(data, null);
            notifyAll();
        }

        public synchronized String pop() throws InterruptedException {
            if (map.size() == 0) {
                wait();
            }
            count.getAndIncrement();
            return map.remove(0);
        }

        public int count() {
            return count.getAndSet(0);
        }
    }


    static class ReadWriteQueue {
        private HashMap<String, String> map = new HashMap<>();
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        private ReentrantReadWriteLock.ReadLock readLock = new ReentrantReadWriteLock().readLock();
        private ReentrantReadWriteLock.WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
        private Condition condition = writeLock.newCondition();
        private AtomicInteger count = new AtomicInteger();
        public void add(String data) {
            writeLock.lock();
            try {
                map.put(data, null);
                condition.signalAll();
            } catch (Exception e) {
            } finally {
                writeLock.unlock();
            }
        }

        public String pop() {
            readLock.lock();
            try {
                if (map.size() == 0)
                    readLock.lock();
                count.getAndIncrement();
                return map.remove(0);
            } catch (Exception e) {
                return null;
            } finally {
                readLock.unlock();
            }
        }

        public int count() {
            return count.getAndSet(0);
        }
    }
}